// 时间段选择组件
import dayjs from "dayjs";

interface IDateBaseProps {
  // 展示时间段（上午 中午 下午）
  showRange: boolean;
  // 提前预约的时间 单位是分钟
  advanceTime: number;
  // 设置天数
  dayNum: number;
  // 间隔时间 单位是分钟
  intervalTime: number;
  // 开始时间
  startTime: string;
  // 结束时间
  endTime: string;
  // 是否单选
  isSingleChoice?: boolean;
  // 不可用样式名
  disabledClsName: string;
  // 时间选中样式
  selectClsName: string;
  // 不可用时描述的样式名
  disabledDescClsName?: string;
  // 时间选中时描述的样式
  selectDescClsName?: string;
  // 不可用提示
  disabledDesc?: string;
  // 正常可用的提示
  desc?: string;
  // 时间可用规则
  timeRules?: {
    // 时间 YYYY-MM-DD HH:mm
    date?: string;
    // 是否可用
    disabled?: boolean;
    desc?: string;
  }[];
  onHandleTime?: (e: ITimeItem) => void;
  onDateChange?: (e: IDateItem) => void;
}
interface ITimeItem {
  time: string;
  date: string;
  passed: boolean; // 是否是过去的时间（与现在的时间进行对比）
  isAdvanceTime?: boolean; // 是否已过提前预约的时间
  select?: boolean;
  [propsName: string]: unknown;
}
interface IDateItem {
  date: string;
  days: string;
  weekDesc: string;
  [propsName: string]: unknown;
}
interface IDateBaseData {
  date: string;
  dateArr: IDateItem[];
  timeItems: ITimeItem[];
  timeItemsRange: ITimeItem[][];
}
const weekList = ["周日", "周一", "周二", "周三", "周四", "周五", "周六"];
const amLimit = "12:00";
const pmLimit = "19:00";
const timeRangeKeys = {
  am: "AM",
  pm: "PM",
  nig: "NIG"
};
Component<IDateBaseData, IDateBaseProps, any>({
  props: {
    advanceTime: 30,
    showRange: true,
    dayNum: 7,
    intervalTime: 30,
    startTime: "09:00",
    endTime: "22:00",
    isSingleChoice: true,
    disabledClsName: "passed",
    selectClsName: "active",
    selectDescClsName: "activeDesc",
    disabledDescClsName: "passedDesc",
    desc: "可预约"
  },
  data: {
    date: dayjs().format("YYYY-MM-DD"),
    timeItemsRange: [],
    dateArr: [],
    timeItems: []
  },
  didMount() {
    this.initDateArr();
    this.initTimeArr();
  },
  didUpdate(prevProps) {
    if (this.judgePropsChange(prevProps)) {
      this.initTimeArr();
    }
    if (prevProps.dayNum !== this.props.dayNum) {
      this.initDateArr();
    }
  },
  methods: {
    changeDate(e) {
      const { date } = e.currentTarget.dataset;
      this.setData({
        date
      });
      this.curTimeDate = dayjs(date)
      this.initTimeArr();
      this.props.onDateChange && this.props.onDateChange(date);
    },
    handleRangeTime(e) {
      const { item, index, timeItemsIndex } = e.currentTarget.dataset;
      let { timeItemsRange } = this.data;
      item.select = !item.select;
      timeItemsRange[timeItemsIndex][index] = item;
      if (this.props.isSingleChoice) {
        timeItemsRange.forEach((dataItems, itemsindex) => {
          dataItems.forEach((data, i) => {
            if (
              timeItemsIndex !== itemsindex ||
              (timeItemsIndex === itemsindex && i !== index)
            ) {
              data.select = false;
            }
          });
        });
      }
      this.setData({
        timeItemsRange
      });
      this.props.onHandleTime && this.props.onHandleTime(item);
    },
    handleTime(e) {
      const { item, index } = e.currentTarget.dataset;
      let { timeItems } = this.data;
      item.select = !item.select;
      timeItems[index] = item;
      if (this.props.isSingleChoice) {
        timeItems.forEach((data, i) => {
          if (i !== index) {
            data.select = false;
          }
        });
      }
      this.setData({
        timeItems
      });
      this.props.onHandleTime && this.props.onHandleTime(item);
    },
    // 初始化日期
    initDateArr() {
      const dateArr = [];
      for (let i = 0; i < this.props.dayNum; i++) {
        const date = dayjs().add(i, "day");
        const days = dayjs(date).format("MM/DD");
        const fullDate = dayjs(date).format("YYYY-MM-DD");
        let weekDesc = weekList[dayjs(date).day()];
        if (i < 3) {
          weekDesc = ["今天", "明天", "后天"][i];
        }
        dateArr.push({ days, weekDesc, date: fullDate });
        this.setData({
          dateArr
        });
      }
    },
    // 初始化时间
    initTimeArr() {
     const date = this.curTimeDate || dayjs();
      const {
        intervalTime,
        startTime,
        endTime,
        disabledDesc,
        desc,
        showRange,
        advanceTime,
        timeRules
      } = this.props;
      const times = [];
      const nowDate = dayjs();
      const curDate = date.format("YYYY-MM-DD");
      const endDate = dayjs(`${curDate} ${endTime}`);
      const startDate = dayjs(`${curDate} ${startTime}`);
      let curTime = startDate;
      const timeRulesMaps = (timeRules || []).map(item => item.date);
      while (curTime <= endDate) {
        const passed = nowDate > curTime;
        const disabled = this.getDisabledByRule(curTime, timeRulesMaps);
        const { timeType, timeDesc, timeTypeDesc } = showRange
          ? this.getTimeRangeDesc({ curTime, startDate, curDate })
          : { timeType: "", timeDesc: "", timeTypeDesc: "" };
        const data = {
          time: curTime.format("HH:mm"),
          date: curTime.format("YYYY-MM-DD HH:mm"),
          passed,
          disabled,
          tips: disabled ? this.curDesc || disabledDesc : this.curDesc || desc,
          select: false,
          timeDesc,
          timeTypeDesc,
          timeType,
          isAdvanceTime: false
        };
        // 必须提前advanceTime分钟预约
        if (advanceTime && nowDate.add(advanceTime, "minute") > curTime) {
          data.tips = `不可预约`;
          data.isAdvanceTime = true;
        }
        //  !passed不展示过去的时间段
        !passed && times.push(data);
        curTime = curTime.add(intervalTime, "minute");
      }
      if (showRange) {
        this.setData({
          timeItemsRange: this.handleTimeRange(times)
        });
      } else {
        this.setData({
          timeItems: times
        });
      }
    },
    // 根据时间规则获取不可预约的状态
    getDisabledByRule(curTime, timeRulesMaps) {
      const { timeRules } = this.props;
      if (timeRules && timeRules.length) {
        const curTimeDesc = dayjs(curTime).format("YYYY-MM-DD HH:mm");
        const index = timeRulesMaps.indexOf(curTimeDesc);
        if (index !== -1) {
          this.curDesc = timeRules[index].desc;
          return timeRules[index].disabled;
        }
        this.curDesc = "";
        return false;
      }
      return false;
    },

    getTimeRangeDesc({ curTime, startDate, curDate }) {
      const amLimitTime = dayjs(`${curDate} ${amLimit}`);
      const pmLimitTime = dayjs(`${curDate} ${pmLimit}`);
      const { startTime, endTime } = this.props;
      let desc: any = {};
      if (curTime >= startDate && curTime < amLimitTime) {
        desc.timeType = timeRangeKeys.am;
        desc.timeTypeDesc = `${startTime}-${amLimit}`;
        desc.timeDesc = "上午";
      } else if (curTime >= amLimitTime && curTime < pmLimitTime) {
        desc.timeType = timeRangeKeys.pm;
        desc.timeTypeDesc = `${amLimit}-${pmLimit}`;
        desc.timeDesc = "下午";
      } else {
        desc.timeType = timeRangeKeys.nig;
        desc.timeTypeDesc = `${pmLimit}-${endTime}`;
        desc.timeDesc = "晚上";
      }
      return desc;
    },

    handleTimeRange(times) {
      const amItems = times.filter(
        (item: IDateItem) => item.timeType === timeRangeKeys.am
      );
      const pmItems = times.filter(
        (item: IDateItem) => item.timeType === timeRangeKeys.pm
      );
      const nigItems = times.filter(
        (item: IDateItem) => item.timeType === timeRangeKeys.nig
      );
      return [amItems, pmItems, nigItems];
    },
    judgePropsChange(prevProps) {
      const {
        advanceTime,
        intervalTime,
        startTime,
        endTime,
        timeRules
      } = this.props;
      if (
        prevProps.timeRules !== timeRules ||
        prevProps.advanceTime !== advanceTime ||
        prevProps.intervalTime !== intervalTime ||
        prevProps.startTime !== startTime ||
        prevProps.endTime !== endTime
      ) {
        return true;
      }  
      return false;
    }
  }
});
